import Redis, { Cluster, ClusterOptions, RedisOptions } from 'ioredis';
import dotenv from 'dotenv';
import path from 'path';
import { getLogger } from '@/utils/logger';

// 创建Redis专用的日志记录器
const logger = getLogger('redis');

// 加载环境变量
const env = process.env.NODE_ENV || 'development';
const envFile = `.env.${env}`;
const defaultEnvFile = '.env';

// 先尝试加载指定环境的配置文件，如果不存在则加载默认.env文件
dotenv.config({ path: path.resolve(process.cwd(), envFile) });
dotenv.config({ path: path.resolve(process.cwd(), defaultEnvFile) });

// Redis配置接口
interface RedisConfig {
  enabled: boolean;
  options: RedisOptions;
}

// 获取环境变量
const REDIS_ENABLED = process.env.REDIS_ENABLED === 'true';
const REDIS_HOST = process.env.REDIS_HOST || '127.0.0.1';
const REDIS_PORT = parseInt(process.env.REDIS_PORT || '6379', 10);
const REDIS_PASSWORD = process.env.REDIS_PASSWORD || '';
const REDIS_DB = parseInt(process.env.REDIS_DB || '0', 10);

// Redis配置
const redisConfig: RedisConfig = {
  enabled: REDIS_ENABLED,
  options: {
    host: REDIS_HOST,
    port: REDIS_PORT,
    password: REDIS_PASSWORD || undefined,
    db: REDIS_DB,
    retryStrategy: (times: number) => {
      // 重试策略：每次重试时间指数增加，最大1000ms
      const delay = Math.min(times * 50, 1000);
      return delay;
    },
    maxRetriesPerRequest: 3
  }
};

// 单节点Redis配置
const redisOptions: RedisOptions = {
	host: redisConfig.options.host,
	port: redisConfig.options.port,
	password: redisConfig.options.password || undefined,
	db: redisConfig.options.db,
	keyPrefix: process.env.REDIS_PREFIX || "ruoyi:",
	connectionName: `ruoyi-node-${env}`,
	keepAlive: parseInt(process.env.REDIS_KEEPALIVE_DELAY || "30000", 10),
	connectTimeout: parseInt(process.env.REDIS_CONNECT_TIMEOUT || "10000", 10),
	retryStrategy(times: number): number | null {
		if (times > (redisConfig.options.maxRetriesPerRequest || 3)) {
			logger.error("Redis连接重试次数超出限制，不再重试");
			return null; // 停止重试
		}
		const delay = Math.min(
			times * 50, // 指数退避策略
			1000 // 最大延迟1秒
		);
		logger.warn(`Redis连接失败，${delay}ms后第${times}次重试...`);
		return delay;
	},
	enableReadyCheck: true,
	enableOfflineQueue: true,
	reconnectOnError(err: Error): boolean {
		const targetError = "READONLY";
		if (err.message.includes(targetError)) {
			// 只在特定错误类型下重连
			return true;
		}
		return false;
	},
	// 增加以下选项，防止连接循环断开
	maxRetriesPerRequest: 3,
	autoResubscribe: true,
	autoResendUnfulfilledCommands: true,
	// 增加TCP保活选项
	enableTLSForSentinelMode: false,
	// 修复类型错误，使用undefined而不是null
	sentinelRetryStrategy: undefined,
	// 设置更长的空闲超时时间
	commandTimeout: 60000 // 设置命令超时为1分钟
};

// 集群配置
const clusterOptions: ClusterOptions = {
  clusterRetryStrategy(times: number): number | null {
    if (times > (redisConfig.options.maxRetriesPerRequest || 3)) {
      logger.error('Redis集群连接重试次数超出限制，不再重试');
      return null; // 停止重试
    }
    const delay = Math.min(
      times * 50,
      1000 // 最大延迟1秒
    );
    logger.warn(`Redis集群连接失败，${delay}ms后第${times}次重试...`);
    return delay;
  },
  enableReadyCheck: true,
  scaleReads: 'all', // 读取操作在所有节点分布
  redisOptions: {
    password: redisConfig.options.password || undefined,
    connectionName: `ruoyi-node-cluster-${env}`,
    connectTimeout: parseInt(process.env.REDIS_CONNECT_TIMEOUT || "10000", 10),
    keyPrefix: process.env.REDIS_PREFIX || 'ruoyi:',
    // 增加以下选项，防止连接循环断开
    keepAlive: parseInt(process.env.REDIS_KEEPALIVE_DELAY || "30000", 10),
    commandTimeout: 60000,
    autoResubscribe: true,
    autoResendUnfulfilledCommands: true
  },
};

// 创建Redis连接实例
let redisClient: Redis | Cluster;

// 设置健康检查和心跳检测定时器
let healthCheckInterval: NodeJS.Timeout;

// 根据配置决定创建单节点实例还是集群实例
if (process.env.REDIS_CLUSTER_ENABLED === 'true' && process.env.REDIS_CLUSTER_NODES) {
  // 解析集群节点
  const nodes = process.env.REDIS_CLUSTER_NODES.split(',').map(node => {
    const [host, port] = node.split(':');
    return { host, port: parseInt(port, 10) };
  });

  // 创建集群实例
  redisClient = new Redis.Cluster(nodes, clusterOptions);
  logger.info(`Redis集群模式已初始化 - 节点数: ${nodes.length}`);
} else {
  // 创建单节点实例
  redisClient = new Redis(redisOptions);
  logger.info(`Redis单节点模式已初始化 - ${REDIS_HOST}:${REDIS_PORT}`);
}

// 监听连接事件
redisClient.on('connect', () => {
  logger.info('Redis连接已建立');
});

redisClient.on('ready', () => {
  logger.info('Redis服务已就绪');
  
  // 清除之前的定时器
  if (healthCheckInterval) {
    clearInterval(healthCheckInterval);
  }
  
  // 设置心跳检测，每60秒发送PING命令
  healthCheckInterval = setInterval(async () => {
    try {
      const result = await redisClient.ping();
      if (result === 'PONG') {
        logger.info("Redis心跳检测成功");
      } else {
        logger.warn(`Redis心跳检测异常响应: ${result}`);
      }
    } catch (error) {
      logger.error(`Redis心跳检测失败: ${(error as Error).message}`);
    }
  }, 60000);
});

redisClient.on('error', (error: Error) => {
  logger.error(`Redis错误: ${error.message}`);
});

redisClient.on('close', () => {
  logger.warn('Redis连接已关闭');
  
  // 连接关闭时清除心跳定时器
  if (healthCheckInterval) {
    clearInterval(healthCheckInterval);
  }
});

redisClient.on('reconnecting', () => {
  logger.info('Redis正在重新连接...');
});

// 优雅关闭Redis连接
export const closeRedisConnection = async (): Promise<void> => {
  if (healthCheckInterval) {
    clearInterval(healthCheckInterval);
  }
  
  if (redisClient) {
    await redisClient.quit();
    logger.info('Redis连接已安全关闭');
  }
};

// 处理应用退出
process.on('SIGINT', async () => {
  await closeRedisConnection();
});

process.on('SIGTERM', async () => {
  await closeRedisConnection();
});

// 修改导出，将redisClient作为默认导出
export { redisConfig };
export default redisClient; 